//
//  HeadlineNews
//
//  Created by han on 2019/7/24.
//  Copyright © 2019 han. All rights reserved.
//

import UIKit

private typealias setCGColorValueIMP = @convention(c) (NSObject, Selector, CGColor) -> Void
private typealias setCGFloatValueIMP = @convention(c) (NSObject, Selector, CGFloat) -> Void
private typealias setValueForStateIMP = @convention(c) (NSObject, Selector, AnyObject, UIControl.State) -> Void
private typealias setScrollValueIMP = @convention(c) (NSObject, Selector, UIScrollView.IndicatorStyle) -> Void
fileprivate typealias setKeyboardValueIMP       = @convention(c) (NSObject, Selector, UIKeyboardAppearance) -> Void
fileprivate typealias setActivityStyleValueIMP  = @convention(c) (NSObject, Selector, UIActivityIndicatorView.Style) -> Void
#if os(iOS)
fileprivate typealias setBarStyleValueIMP       = @convention(c) (NSObject, Selector, UIBarStyle) -> Void
fileprivate typealias setStatusBarStyleValueIMP = @convention(c) (NSObject, Selector, UIStatusBarStyle, Bool) -> Void
#endif


// MARK: -
typealias ThemePickers = [String: ThemePicker]
private var themePickersKey = ""

extension NSObject {
    var themePickers: ThemePickers {
        get {
            if let themePickers = objc_getAssociatedObject(self, &themePickersKey) as? ThemePickers {
                return themePickers
            }
            let initValue = ThemePickers()
            objc_setAssociatedObject(self, &themePickersKey, initValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            return initValue
        }
        set {
            objc_setAssociatedObject(self, &themePickersKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            removeThemeNotification()
            if newValue.isEmpty == false { setupThemeNotification() }
        }
    }
}

extension NSObject: ThemeExtendProtocol{}
extension ThemeExtended where T: NSObject {
   
    func performPicker(selector: String, picker: ThemePicker?) {
        let sel = Selector(selector)
        
        guard value.responds(to: sel) else { return }
        
        guard let pickerValue = picker?.value() else { return }
        
        if let statePicker = picker as? ThemeStatePicker {
            let setState = unsafeBitCast(value.method(for: sel), to: setValueForStateIMP.self)
            statePicker.values.forEach {
                guard let subvalue = $1.value() else { return }
                setState(value, sel, subvalue as AnyObject, UIControl.State(rawValue: $0))
            }
        }
        else if picker is ThemeCGColorPicker {
            // 将selector强制转换为 setCGColorValueIMP这种类型的
            let setCGColor = unsafeBitCast(value.method(for: sel), to: setCGColorValueIMP.self)
            setCGColor(value, sel, pickerValue as! CGColor)
        }
        else if picker is ThemeCGFloatPicker {
            let setCGFloat = unsafeBitCast(value.method(for: sel), to: setCGFloatValueIMP.self)
            setCGFloat(value, sel, pickerValue as! CGFloat)
        }
        else if picker is ThemeScrollViewIndicatorStylePicker {
            let setIndicator = unsafeBitCast(value.method(for: sel), to: setScrollValueIMP.self)
            setIndicator(value, sel, pickerValue as! UIScrollView.IndicatorStyle)
        }
        else if picker is ThemeBarStylePicker {
            #if os(iOS)
            let setBarStyle = unsafeBitCast(value.method(for: sel), to: setBarStyleValueIMP.self)
            setBarStyle(value, sel, pickerValue as! UIBarStyle)
            #endif
        }
            
        else if picker is ThemeKeyboardAppearancePicker {
            let setKeyboard = unsafeBitCast(value.method(for: sel), to: setKeyboardValueIMP.self)
            setKeyboard(value, sel, pickerValue as! UIKeyboardAppearance)
        }
            
        else if picker is ThemeActivityIndicatorViewStylePicker {
            let setActivityStyle = unsafeBitCast(value.method(for: sel), to: setActivityStyleValueIMP.self)
            setActivityStyle(value, sel, pickerValue as! UIActivityIndicatorView.Style)
        }
        else if let statusBarStylePicker = picker as? ThemeStatusBarStylePicker {
            #if os(iOS)
            let setStatusBarStyle = unsafeBitCast(value.method(for: sel), to: setStatusBarStyleValueIMP.self)
            setStatusBarStyle(value, sel, pickerValue as! UIStatusBarStyle, statusBarStylePicker.animated)
            #endif
        }
        else {
            // setUIColor; setUIImage; setUIFont; setDictionary
            // 可以直接perform 调用
            value.perform(sel, with: pickerValue)
        }
        
    }
    
}

// notifaication
extension NSObject {
    private func setupThemeNotification() {
        if #available(iOS 9.0, tvOS 9.0, *) {
            NotificationCenter.default.addObserver(self, selector: #selector(updateTheme), name: NSNotification.Name(rawValue: ThemeUpdateNotification), object: nil)
        } else {
            NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: ThemeUpdateNotification), object: nil, queue: nil) { [weak self] notification in
                self?.updateTheme()
            }
        }
    }
    
    private func removeThemeNotification() {
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: ThemeUpdateNotification), object: nil)
    }
    
    @objc private func updateTheme() {
        themePickers.forEach { selector, picker in
            UIView.animate(withDuration: ThemeManager.animationDuration, animations: {
                self.theme.performPicker(selector: selector, picker: picker)
            })
        }
    }
}
